#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
 
typedef struct{
	ngx_str_t hello_string;
	ngx_http_complex_value_t  *tokens;
	ngx_http_complex_value_t  *tokens_test;


	ngx_int_t hello_counter;
} ngx_http_hello_loc_conf_t;

static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf);

static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf);
/*
static char *ngx_http_hello_string(ngx_conf_t *cf,ngx_command_t *cmd,void *conf);

static char *ngx_http_hello_counter(ngx_conf_t *cf,ngx_command_t *cmd, void *conf);
*/

static char *ngx_http_set_tokens_test_slot(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf);


static ngx_command_t ngx_http_hello_commands[] = {
	{ngx_string("hello_string"),
	NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
	ngx_conf_set_str_slot,
	NGX_HTTP_LOC_CONF_OFFSET,
	offsetof(ngx_http_hello_loc_conf_t,hello_string),
    NULL},

    {ngx_string("tokens"),
	NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
	ngx_http_set_complex_value_slot,
	NGX_HTTP_LOC_CONF_OFFSET,
	offsetof(ngx_http_hello_loc_conf_t,tokens),
    NULL},

     {ngx_string("tokens_test"),
	NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
	ngx_http_set_tokens_test_slot,
	NGX_HTTP_LOC_CONF_OFFSET,
	offsetof(ngx_http_hello_loc_conf_t,tokens_test),
    NULL},

    {
    	ngx_string("hello_counter"),
    	NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
    	ngx_conf_set_flag_slot,
    	NGX_HTTP_LOC_CONF_OFFSET,
    	offsetof(ngx_http_hello_loc_conf_t,hello_counter),
    	NULL
    },
    ngx_null_command
};


static int ngx_hello_visited_times = 0 ;

static ngx_http_module_t ngx_http_too_module_ctx = {
	NULL, /*preconfiguration */
	ngx_http_hello_init, /*postconfiguration */
	NULL,  /* create main configuration */
	NULL, /*init main configuration */

	NULL,   /*create server configuration */
	NULL,   /*merge server configuration */

	ngx_http_hello_create_loc_conf,  /*create location configuration */
	NULL    /* merge location configuration */
};

ngx_module_t ngx_http_too_module = {
	NGX_MODULE_V1,
	&ngx_http_too_module_ctx,    /*module context */
	ngx_http_hello_commands,       /* module directives */
	NGX_HTTP_MODULE,               /* module type */
	NULL,                          /* init master */
	NULL,							/*init module */
	NULL,							/*int process */
	NULL,							/*init thread */
	NULL,							/* exit thread */
	NULL,							/* exit process */
	NULL,							/* exit master */
	NGX_MODULE_V1_PADDING
};


char *ngx_http_set_tokens_test_slot(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf){
	ngx_http_hello_loc_conf_t *alcf = conf;

    ngx_str_t                         value = ngx_string("");
    ngx_http_compile_complex_value_t   ccv;
    
    char *part=ngx_pcalloc(cf->pool,sizeof(char *));
    strncat(part,"sectres",7);
    strncat(part,"$remote_addr",12);
    strncat(part,"$1",2);


    value.data=(u_char *)part;
    value.len=strlen(part);  
    
  alcf->tokens_test=ngx_pcalloc(cf->pool,sizeof(ngx_http_complex_value_t));
    
    

    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

    ccv.cf = cf;
    ccv.value = &value;
    ccv.complex_value = alcf->tokens_test;
   
      if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    ngx_log_error(NGX_LOG_EMERG, cf->log,0,"ngx_http_set_tokens_test_slot %V",&value);


    return NGX_CONF_OK;
}


static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r){
	ngx_int_t rc;
	ngx_buf_t *b;
	ngx_str_t tokens,tokens_test;
	ngx_chain_t out;
	ngx_http_hello_loc_conf_t* my_conf;
	u_char ngx_hello_string[1024] = {0};
	ngx_uint_t content_length  = 0;

	ngx_log_error(NGX_LOG_EMERG, r->connection->log,0,"ngx_http_hello_handler is called!");



	my_conf = ngx_http_get_module_loc_conf(r,ngx_http_too_module);

	if (ngx_http_complex_value(r, my_conf->tokens, &tokens) != NGX_OK) {
        return NGX_ERROR;
    }

        		ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"tokens====== %V",&tokens);

      if (ngx_http_complex_value(r, my_conf->tokens_test, &tokens_test) != NGX_OK) {
        return NGX_ERROR;
    }

        		ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"tokens_test====== %V",&tokens_test);

        		  		

	if(my_conf->hello_string.len == 0){
		ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"hello string is empty!");
		return NGX_DECLINED;
	}



/*
 ngx_http_core_loc_conf_t* clcf;
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    ngx_str_t *myvs;
    ngx_str_set(myvs,"abcv");
    ngx_int_t index=ngx_http_get_variable_index(clcf,*myvs);
    ngx_http_variable_value_t  *myva=ngx_http_get_indexed_variable(r,
      index);
	ngx_log_error(NGX_LOG_EMERG, r->connection->log,0,"myvs :%s",myva->data);*/
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    ngx_uint_t i;
    ngx_http_variable_t        *vsss;
    vsss=cmcf->variables.elts;
    for (i = 0; i < cmcf->variables.nelts; ++i)
    {
    	vsss[i].get_handler(r, &r->variables[i], vsss[i].data);
    }




	if(my_conf->hello_counter == NGX_CONF_UNSET || my_conf->hello_counter == 0){
		ngx_sprintf(ngx_hello_string,"%s",my_conf->hello_string.data);
	}  else{
		ngx_sprintf(ngx_hello_string,"%s Visited Times:%d",my_conf->hello_string.data,++ngx_hello_visited_times);
	}

	ngx_log_error(NGX_LOG_EMERG,r->connection->log,0,"hello_string:%s",ngx_hello_string);
	content_length = ngx_strlen(ngx_hello_string);

	/* we response to 'GET' and 'HEAD' requests only */
	if (!(r->method &(NGX_HTTP_GET|NGX_HTTP_HEAD)))
	{
		return NGX_HTTP_NOT_ALLOWED;
	}

	/* discard request body, since we don't need it here */
	rc = ngx_http_discard_request_body(r);

	if (rc!=NGX_OK)
	{
		return rc;
	}

	/** set the 'Content-type' header */
	/**
	* r->headers_out.content_type.len = sizeof("text/")
    * r->headers_out.content_type.data = (u_char *)"text/html";
	*/

	ngx_str_set(&r->headers_out.content_type,"text/html");
	if(r->method == NGX_HTTP_HEAD){
		r->headers_out.status = NGX_HTTP_OK;
		r->headers_out.content_length_n = content_length;

		return ngx_http_send_header(r);
	}

	b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

	if(b == NULL){
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}

	/* attch this buffer to the buffer chain */
	out.buf = b;
	out.next = NULL;

	/* adjust the pointers of the buffer */
	b->pos = ngx_hello_string;
	b->last = ngx_hello_string + content_length;
	b->memory = 1; /*this buffer is in memory */
	b->last_buf = 1; /* this is the last buffer in the buffer chain */

	/*set the status line */
	r->headers_out.status = NGX_HTTP_OK;
	r->headers_out.content_length_n = content_length;

	/* send the headers of your response */
	rc = ngx_http_send_header(r);

	if (rc == NGX_ERROR || rc>NGX_OK || r->header_only)
	{
		return rc;
	}

	/*send the buffer chain of your response */

	return ngx_http_output_filter(r,&out);
}


static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf){
	ngx_http_hello_loc_conf_t* local_conf = NULL;
	local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
	if (local_conf == NULL)
	{
		return NULL;
	}

	ngx_str_null(&local_conf->hello_string);
    local_conf->hello_counter = NGX_CONF_UNSET;

    return local_conf;
}
 


static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf){
	ngx_http_handler_pt *h;
	ngx_http_core_main_conf_t *cmcf;

	cmcf = ngx_http_conf_get_module_main_conf(cf,ngx_http_core_module);

	h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
	if(h == NULL ){
		return NGX_ERROR;
	}

	*h = ngx_http_hello_handler;

 int rc, captures[14];
	    ngx_str_t pattern = ngx_string("(?<ET>\\$\\d),(?<expectToken>\\$\\d)=(?<token>.*)");
	    ngx_str_t unparsed_uri = ngx_string("$1,$2=sectresClientIP$3");
	    ngx_regex_compile_t rgc;
	    ngx_memzero(&rgc, sizeof(ngx_regex_compile_t));
   u_char errstr[NGX_MAX_CONF_ERRSTR];

	  rgc.pattern  = pattern;
    rgc.pool     = cf->pool;
    rgc.err.len  = NGX_MAX_CONF_ERRSTR;
    rgc.err.data = errstr;
   ngx_regex_compile(&rgc);

   rc = ngx_regex_exec(rgc.regex, &unparsed_uri, captures, 14);
            		ngx_log_error(NGX_LOG_EMERG,cf->log,0,"tokens====== %d",rc);


	return NGX_OK;
}